﻿namespace clowncar
{
    using System;
    using System.Collections.Generic;
    using System.Threading;
    using Mono.Options;
    using clowncar.Utils;

    class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        //[STAThread]
        static int Main(string[] args)
        {
            //Application.ThreadException += MyApplication_ThreadException;
            AppDomain.CurrentDomain.UnhandledException += MyApplication_UnhandledException;
            AppDomain.CurrentDomain.AssemblyResolve += AssemblyUtils.AssemblyResolver;
            var ctx = new AppContext();
            return ctx.Run(args);
        }

        private static void MyApplication_ThreadException(object sender, ThreadExceptionEventArgs e)
        {
            GlobalExceptionHandler(e.Exception);
        }

        private static void MyApplication_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            GlobalExceptionHandler((Exception)e.ExceptionObject);
        }

        private static void GlobalExceptionHandler(Exception e)
        {
            //Log.WriteLine(e.ToString());
            IOUtils.ConsoleError("Unhandled exception", e);
            if (e.InnerException != null)
            {
                Console.WriteLine("Inner exception...", null);
                //Log.Write("Inner exception:...");
                //GlobalExceptionHandler(e.InnerException);
            }
        }

        //Create a special App context to avoid the generic icon problem at startup
        public class AppContext 
        {
            Settings settings = new Settings();

            public int Run(string[] args)
            {
                bool show_help = false;

                var p = new OptionSet() {
                { "u|url=",     "The file to download", v => settings.Url=v},
                { "n|unzip",    "Does the downloaded file need unzipping?", v => settings.Unzip = v != null},
                { "p|path=",    "The path to store the file, once downloaded", v => settings.LocalPath = v},
                { "r|runit",    "Does the downloaded file need to be run?", v => settings.RunIt = v != null},
                { "a|args=",    "Arguments to pass to the file, if running it", v => settings.Args = v},
                { "z|zip=",     "Name of file to unzip, if already present", v => settings.TempFileName = v},
                { "e|exec=",    "Name of file to execute", v => settings.TargetFileName = v},
                { "?|h|help",   "Show this message and exit.", 
              v => show_help = v != null },
            };

                List<string> extra;
                try
                {
                    extra = p.Parse(args);
                }
                catch (OptionException e)
                {
                    IOUtils.ConsoleError("Error parsing arguments", e);

                    return 1;
                }

                if (settings.TempFileName != null && !settings.Unzip)
                {
                    //If they specified a zip file, then they want to unzip it, even if they
                    //didn't say 'unzip'.
                    settings.Unzip = true;
                }
                if (settings.TargetFileName != null && !settings.RunIt)
                {
                    //If they specified a file to execute, then they want to execute it, even if they
                    //didn't say 'runit'.
                    settings.RunIt = true;
                }
                
                if (show_help)
                {
                    ShowHelp(p);
                    return 0;
                }

                //Validate arguments.
                if (string.IsNullOrEmpty(settings.LocalPath))
                {
                    IOUtils.ConsoleError("No Path specified", null);
                    return 2;
                }

                //If no URL specified... that's ok.
                if (!string.IsNullOrEmpty(settings.Url))
                {
                    settings.TempFileName = System.IO.Path.GetTempFileName();

                    //Download the file to the temp file name
                    if (!settings.Download())
                    {
                        return 3;
                    }
                }

                if (settings.Unzip)
                {
                    settings.UnzipTarget();
                }
                
                if (!settings.Wait())
                {
                    return 4;
                }

                if (settings.Unzip)
                {
                    settings.CopyZipContents();
                }
                else
                {
                    settings.Copy();
                }
                settings.Execute();

                return 0;
            }

            static void ShowHelp(OptionSet p)
            {
                Console.Write("Usage: ");
                Console.ForegroundColor = ConsoleColor.White;
                Console.Write("GrabAndRun ");
                Console.ResetColor();
                Console.WriteLine("options");
                Console.WriteLine("Download a file and/or unzip it, and/or run it, with arguments.");
                Console.WriteLine();
                Console.WriteLine("Options:");
                p.WriteOptionDescriptions(Console.Out);
            }
        }
    }
}